#include "device.h"
#include "protocol.h"

device_info_t gDevice = {0};

/// 配置：滑动窗口大小
#define WINDOW_SIZE     5
#define FILTER_CHANNELS 2

/// 滤波器状态结构体（Linux 风格命名）
typedef struct {
    float buf[WINDOW_SIZE];  ///< 样本环形缓冲区
    uint8_t idx;             ///< 下一个写入索引
    uint8_t count;           ///< 当前缓冲区有效样本数量
    float sum;               ///< 样本总和，用于快速计算平均值
} moving_avg_t;

/// 全局滤波器实例，自动初始化为 0
static moving_avg_t g_filters[FILTER_CHANNELS];

/**
 * @brief  更新指定通道滤波器并返回平滑结果
 *
 *         对指定通道最近 WINDOW_SIZE 个样本做滑动平均。
 *         缓冲区未满时，按已有样本数计算平均。
 *
 * @param  ch   通道下标（0 ~ FILTER_CHANNELS-1）
 * @param  raw  新输入的原始样本值（int8_t 类型）
 * @return      平滑后的平均值（int8_t 类型，四舍五入并限幅）
 */
int8_t filter_update(uint8_t ch, int8_t raw)
{
    float avg = 0.0f;
    int16_t tmp = 0;
    moving_avg_t *f = &g_filters[ch];

    if (ch >= FILTER_CHANNELS) {
        return raw;
    }

    // 缓冲区满则减去最旧样本
    if (f->count == WINDOW_SIZE) {
        f->sum -= f->buf[f->idx];
    }
    else {
        f->count++;
    }

    // 存入新样本并累加总和
    f->buf[f->idx] = (float)raw;
    f->sum += (float)raw;

    // 更新写入索引
    f->idx = (f->idx + 1) % WINDOW_SIZE;

    // 计算平均值
    avg = f->sum / f->count;

    // 四舍五入并转换为 int8_t，防止溢出
    if (avg >= 0) {
        tmp = (int16_t)(avg + 0.5f);
    }
    else {
        tmp = (int16_t)(avg - 0.5f);
    }
    if (tmp > INT8_MAX)
        tmp = INT8_MAX;
    if (tmp < INT8_MIN)
        tmp = INT8_MIN;
    return (int8_t)tmp;
}

void registry_params(void)
{
    uint8_t ch;
    Registry_Param(ParamID_CWNumber, gDevice.cwNumber);
    for (ch = 0; ch < gDevice.cwNumber; ch++) {
        Registry_Param(ParamID_WorkFreqcommunicationMode_CW1 + ch * 1, gDevice.workFreqComMode[ch]);
        Registry_Param(ParamID_UpMaxGainOne + ch * 2, gDevice.upCwMaxGain[ch]);
        Registry_Param(ParamID_DnMaxGainOne + ch * 2, gDevice.dnCwMaxGain[ch]);

        Registry_Param(ParamID_UpAttenuation_CH1 + ch * 2, gDevice.upAttenuation[ch]);
        Registry_Param(ParamID_DnAttenuation_CH1 + ch * 2, gDevice.dnAttenuation[ch]);

        Registry_Param(ParamID_DnOutPowerOne + ch * 6, gDevice.dnOutPower[ch]);
        Registry_Param(ParamID_UpOutPowerOne + ch * 6, gDevice.upOutPower[ch]);

        Registry_Param(ParamID_UpOutOverPowerAlarmOne + 6 * ch, gDevice.up_over_power_alarm[ch]);
        Registry_Param(ParamID_DnOutLackPowerAlarmOne + 6 * ch, gDevice.dn_lack_power_alarm[ch]);
        Registry_Param(ParamID_DnOutOverPowerAlarmOne + 6 * ch, gDevice.dn_over_power_alarm[ch]);

        Registry_Param(ParamID_UpRatedPowerOne + ch * 2, gDevice.upCwRatedPower[ch]);
        Registry_Param(ParamID_DnRatedPowerOne + ch * 2, gDevice.dnCwRatedPower[ch]);
    }
}

void default_device_info(void)
{
    uint8_t ch;
    gDevice.cwNumber = 3;
    for (ch = 0; ch < gDevice.cwNumber; ch++) {
        gDevice.workFreqComMode[ch] = 0;
        gDevice.upCwMaxGain[ch] = 0;
        gDevice.dnCwMaxGain[ch] = 0;

        gDevice.upAttenuation[ch] = 0;
        gDevice.dnAttenuation[ch] = 0;

        gDevice.upOutPower[ch] = 0;
        gDevice.dnOutPower[ch] = 0;

        gDevice.up_over_power_alarm[ch] = 0;
        gDevice.dn_lack_power_alarm[ch] = 0;
        gDevice.dn_over_power_alarm[ch] = 0;
    }
}

void inid_device_info(void)
{
    memset(&gDevice, 0, sizeof(gDevice));
    default_device_info();
    registry_params();
}

#define CDMA800   10
#define EGSM900   5
#define GSM1800   7
#define WCDMA2100 16
#define TD2600    33
#define TD3500    38

char *get_system_name_by_code(uint8_t code)
{
    switch (code) {
        case CDMA800:
            return " Band 5";
        case EGSM900:
            return " Band 8";
        case GSM1800:
            return " Band 3";
        case WCDMA2100:
            return " Band 1";
        case TD2600:
            return "    N41";
        case TD3500:
            return "    N78";
        default:
            return "UNKNOWN";
    }
}
